﻿using CleanArchitecture.Core.Configuration;
using CleanArchitecture.Core.Handlers;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Infrastructure.Entities.Customers;
using CleanArchitecture.Infrastructure.Interfaces;
using CleanArchitecture.Infrastructure.Interfaces.AdminUsers;
using CleanArchitecture.Infrastructure.Interfaces.Customers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Linq;

namespace CleanArchitecture.Web.Filters
{
    /// <summary>
    /// Represents a filter attribute that confirms access to the front authentication field
    /// </summary>
    public class AuthorizeCustomerAttribute : TypeFilterAttribute
    {
        #region Fields

        private readonly AuthorizeType _ignoreFilter;

        #endregion

        #region Ctor

        /// <summary>
        /// Create instance of the filter attribute
        /// </summary>
        /// <param name="ignore">Whether to ignore the execution of filter actions</param>
        public AuthorizeCustomerAttribute(AuthorizeType ignore = AuthorizeType.Forbidden) : base(typeof(AuthorizeCustomerFilter))
        {
            _ignoreFilter = ignore;
            Arguments = new object[] { ignore };
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether to ignore the execution of filter actions
        /// </summary>
        public AuthorizeType IgnoreFilter => _ignoreFilter;

        #endregion


        #region Nested filter

        /// <summary>
        /// Represents a filter that confirms access to the admin panel
        /// </summary>
        private class AuthorizeCustomerFilter : IAuthorizationFilter
        {
            #region Fields

            private readonly AuthorizeType _ignoreFilter;
            private readonly IWorkContext _workContext;
            private readonly bool _isDevelopment;
            private readonly IWebHelper _webHelper;

            #endregion

            #region Ctor

            public AuthorizeCustomerFilter(AuthorizeType ignoreFilter,
                IWorkContext workContext,
                IWebHelper webHelper)
            {
                _ignoreFilter = ignoreFilter;
                _workContext = workContext;
                _isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
                _webHelper = webHelper;
            }

            #endregion

            #region Methods

            /// <summary>
            /// Called early in the filter pipeline to confirm request is authorized
            /// </summary>
            /// <param name="filterContext">Authorization filter context</param>
            public void OnAuthorization(AuthorizationFilterContext filterContext)
            {
                if (filterContext == null)
                    throw new ArgumentNullException(nameof(filterContext));


                Customer customer = null;
                //check whether this filter has been overridden for the action
                //DavidLee 2019/11/23 验证后台授权的两种方式
                // 1： 在Controller下的action方法上指定Attribute: [AuthorizeAdmin(AuthorizeType.Forbidden)]
                //     AuthorizeType 默认为Forbidden ：登录用户才可以访问
                //                        Ignore : 在后台页面方法前使用[AuthorizeAdmin(AuthorizeType.Ignore)]，则任何用户可以访问，不进行授权拦截
                // 2:  在Controller下的action方法上指定Attribute: [AllowAnonymous]
                var actionFilter = filterContext.ActionDescriptor.FilterDescriptors
                    .Where(filterDescriptor => filterDescriptor.Scope == FilterScope.Action)
                    .Select(filterDescriptor => filterDescriptor.Filter).OfType<AuthorizeCustomerAttribute>().FirstOrDefault();
                
                //ignore filter (the action is available even if a customer hasn't access to the admin area)
                if(actionFilter?.IgnoreFilter.GetType() == typeof(AuthorizeType))
                {
                    var filterArg = actionFilter?.IgnoreFilter ?? _ignoreFilter;
                    if (filterArg == AuthorizeType.Ignore && _isDevelopment)
                        return;
                }

                if (filterContext.Filters.Any(filter => filter is AllowAnonymousFilter) && _isDevelopment)
                {
                    //如果用户方位的Action带有AllowAnonymousAttribute，则不进行授权验证
                    customer = _workContext.CurrentCustomer;
                    if (customer == null) //伪造用户信息，绕过授权验证方便调试开发，但要确保数据库中有用户手机号为13388859505的用户数据
                        _workContext.CurrentCustomer = EngineContext.Current.Resolve<ICustomerService>().GetCustomerByMobile("13388859505");
                    return;
                }
                //there is AdminAuthorizeFilter, so check access
                if (filterContext.Filters.Any(filter => filter is AuthorizeCustomerFilter))
                {

                    customer = _workContext.CurrentCustomer;
                    if(customer == null)
                        filterContext.Result = new ChallengeResult();
                }
            }

            #endregion
        }

        #endregion
    }
}
